﻿/*
	CaptivatePlayer
	
	*** Updated 7.9.2005
		- added continousPlayback option to play back each movie 
		automatically one after the other
		- added looping so the entire presentation can loop when the last movie is done
		- added both properties to XML parser (SWFListMaker.as)
	
	*** Updated 3.13.2005
		- changed classpath
		- extend mx.core.View instead of mx.core.UIComponent
		- modified some properties to be getter/setters
	
	
	Plays a list of SWF's read from an external
	XML file.  This XML file has the ability to
	configure the player as well as well providing
	a list of SWF's + the name that will display
	them in the Section's menu.
	
	Additionally, the player can be configured
	ahead of time, overriding the default values
	via FlashVars.  The FLA that should be included
	shows an example of this.  However, if there are
	attribute values in the XML file, the will
	override whatever you set here.
	
	XML Format
	----------
	<captivate_playlist
		autoplay="false" // values: "false" or "true"; play first SWF automatically
		volume="50" // values: 1 through 100; starting volume
		scalecontent="false" > // values: "false" or "true"; whether or not to scale the loaded SWF's
		<swf src="filepath/filename.swf" name="Section Name of SWF" />
		<swf src="filepath/filename.swf" name="Section Name of SWF" />
		<swf src="filepath/filename.swf" name="Section Name of SWF" />
	</captivate_playlist>
	
	Created by Jesse R. Warden a.k.a. "JesterXL"
	jesterxl@jessewarden.com
	http://www.jessewarden.com
	11.19.2004
	
	This is release under a Creative Commons license. 
    More information can be found here:
    
    http://creativecommons.org/licenses/by/2.5/
*/

import mx.core.View;

import mx.controls.Menu;
import mx.controls.MenuBar;
import mx.controls.Label;
import mx.controls.Loader;
import mx.controls.ProgressBar;
import mx.utils.Delegate;
import mx.managers.PopUpManager;

import com.jxl.controls.SimpleSlider;
import com.jxl.captivate.SWFListMaker;
import com.jxl.captivate.SWFProgressWatcher;

[IconFile("CaptivatePlayer.png")]

[TagName("CaptivatePlayer")]

[InspectableList("movies", "autoPlay", "scaleContent", "volume")]

class com.jxl.captivate.CaptivatePlayer extends View
{
	// group: UIComponent variables
	static var symbolName:String = "com.jxl.captivate.CaptivatePlayer";
	static var symbolOwner:Object = com.jxl.captivate.CaptivatePlayer;
	public var className:String = "CaptivatePlayer";
	
	// group: private
	private var xmlparser:SWFListMaker;
	private var swf_array:Array;
	private var oldVolume:Number = 50;
	private var my_sound:Sound;
	private var progress_window;
	private var menusInited:Boolean;
	private var currentWatchID:Number;
	private var _autoPlay:Boolean = true;
	private var _scaleContent:Boolean = true;	
	private var _volume:Number;
	private var _movies:Array;
	private var _continousPlayback:Boolean = true;
	private var _loop:Boolean = false;
	
	// group: getter/setters
	public function get dataProvider():Array
	{
		return swf_array;
	}
	
	public function set dataProvider(val:Array):Void
	{
		swf_array.removeEventListener("modelChanged", this);
		swf_array = val;
		swf_array.addEventListener("modelChanged", this);
		modelChanged();
	}
	
	public function get autoPlay():Boolean
	{
		return _autoPlay;
	}
	
	[Inspectable(defaultValue=true, name="Auto-play", type="Boolean")]
	public function set autoPlay(val:Boolean):Void
	{
		_autoPlay = true;
		
	}
	
	public function get scaleContent():Boolean
	{
		return _scaleContent;
	}
	
	[Inspectable(defaultValue=false, name="Scale Content", type="Boolean")]
	public function set scaleContent(val:Boolean):Void
	{
		_scaleContent = val;
		content_ldr.scaleContent = _scaleContent;
		var item = prefs_mnu.getItemAt(0);
		item.attributes.selected = _scaleContent;
		prefs_mnu.replaceItemAt(0, item);
	}
	
	public function get volume():Number
	{
		return _volume;
	}
	
	[Inspectable(defaultValue=50, name="Volume", type="Number")]
	public function set volume(val:Number):Void
	{
		if(isNaN(val)) return;
		_volume = val;
		oldVolume = _volume;
		my_sound.setVolume(_volume);
		slider_mc.sliderValue = _volume;
	}
	
	public function get movies():Array
	{
		return _movies;
	}
	
	[Inspectable(name="Captivate Movies", type="Array")]
	public function set movies(val:Array):Void
	{
		_movies = val;
		dataProvider = _movies;
	}
	
	[Inspectable(defaultValue=true, name="Continous Playback", type="Boolean")]
	public function get continousPlayback():Boolean
	{
		return _continousPlayback;
	}
	
	public function set continousPlayback(val:Boolean):Void
	{
		_continousPlayback = val;
		setContinousPlayback(_continousPlayback);
	}
	
	[Inspectable(defaultValue=true, name="Loop Playback", type="Boolean")]
	public function get isLooping():Boolean
	{
		return _loop;
	}
	
	public function set isLooping(val:Boolean):Void
	{
		_loop = val;
		setIsLooping(_loop);
	}
		
	
	// group: controls
	private var menu_mb:MenuBar;
	private var sections_mnu:Menu;
	private var prefs_mnu:Menu;
	private var content_ldr:Loader;
	private var slider_mc:SimpleSlider;
	private var volume_lbl:Label;
	private var swfWatcher_mc:SWFProgressWatcher;
	private var boundingBox_mc:MovieClip;
	
	// group: methods
	function CaptivatePlayer()
	{
	}
	
	
	public function init():Void
	{
		super.init();
		
		menusInited = false;
		
		xmlparser = new SWFListMaker();
		xmlparser.addEventListener("load", 
								   Delegate.create(this, onSWFListLoaded));
		swf_array = [];
		swf_array.addEventListener("modelChanged", this);
		
		my_sound = new Sound(this);
		my_sound.setVolume(volume);
		
		//debug("default volume is 50: " + volume);
	}
	
	/*
	private function debug(o)
	{
		dispatchEvent({type: "debug", target: this, text: o});
	}
	*/
	
	private function createChildren():Void
	{
		super.createChildren();
		
		createChild(MenuBar, "menu_mb");
		menu_mb.addEventListener("change", this);
		
		createChild(Loader, "content_ldr");
		content_ldr.autoLoad = true;
		content_ldr.scaleContent = scaleContent;
		content_ldr.addEventListener("complete", this);
		content_ldr.addEventListener("progress", this);
		content_ldr.setStyle("borderStyle", "inset");
		
		createChild(Label, "volume_lbl");
		volume_lbl.text = "Volume:";
		
		createChild(SimpleSlider, "slider_mc");
		slider_mc.sliderValue = oldVolume;
		slider_mc.addEventListener("change", Delegate.create(this, onSlide));
		
		createChild(SWFProgressWatcher, "swfWatcher_mc");
		swfWatcher_mc.addEventListener("onMovieDone", this);
	}
	
	private function doLayout():Void
	{
		super.doLayout();
		
		menu_mb.setSize(width, menu_mb.height);
		
		content_ldr.move(menu_mb.x + 4, menu_mb.y + menu_mb.height + 4);
		content_ldr.setSize(width - 8, height - content_ldr.y - 8);
		
		volume_lbl.move(240, 2);
		slider_mc.move(292, 3);
		
		progress_window.move((width / 2) - (progress_window.width / 2),
							 menu_mb.y + menu_mb.height + 20);
	}
	
	private function initMenus():Void
	{
		menu_mb.removeMenuAt(0);
		menu_mb.removeMenuAt(1);
		
		sections_mnu.removeAll();
		sections_mnu = menu_mb.addMenuAt(0, "Sections");
		var howMany:Number = swf_array.length;
		for(var i:Number = 0; i<howMany; i++)
		{
			var item = swf_array.getItemAt(i);
			sections_mnu.addMenuItem({label: item.label, instanceName: item.data});
		}
		
		prefs_mnu.removeAll();
		prefs_mnu = menu_mb.addMenu(1, "Preferences");
		prefs_mnu.addMenuItem({label: "Scale Content", instanceName: "scale", selected: scaleContent, type: "check"});
		var bool:Boolean = (oldVolume == 0) ? true : false;
		prefs_mnu.addMenuItem({label: "Mute", instanceName: "mute", selected: bool, type: "check"});
		var bool:Boolean = (_continousPlayback == true) ? true : false;
		prefs_mnu.addMenuItem({label: "Play Next Section Automatically", instanceName: "continous", selected: bool, type: "check"});
		var bool:Boolean = (_loop == true) ? true : false;
		prefs_mnu.addMenuItem({label: "Loop Entire Demonstration", instanceName: "loop", selected: bool, type: "check"});
		
		menusInited = true;
	}
	
	public function loadPlaylist(filepath:String):Void
	{
		enabled = false;
		menusInited = false;
		xmlparser.loadXML(filepath);
	}
	
	private function updateShown(item):Void
	{
		if(menusInited == false)
			return;
			
		var label:String = item.attributes.label;
		var i:Number = swf_array.length;
		while(i--)
		{
			var o = sections_mnu.getMenuItemAt(i);
			var lbl:String = o.attributes.label;
			if(label == lbl)
			{
				o.attributes.icon = "CheckIcon";
				sections_mnu.removeMenuItemAt(i);
				sections_mnu.addMenuItemAt(i, o);
				return;
			}
		}
	}
	
	private function setContinousPlayback(val:Boolean):Void
	{
		if(menusInited == false)
			return;
		
		var c:Object = prefs_mnu.getMenuItemAt(2);
		c.attributes.selected = val;
		prefs_mnu.removeMenuItemAt(2);
		prefs_mnu.addMenuItemAt(2, c);
	}
	
	private function setIsLooping(val:Boolean):Void
	{
		trace("setIsLooping: " + val);
		if(menusInited == false)
			return;
		
		var c:Object = prefs_mnu.getMenuItemAt(3);
		c.attributes.selected = val;
		trace("c.attributes.selected: " + c.attributes.selected);
		prefs_mnu.removeMenuItemAt(3);
		prefs_mnu.addMenuItemAt(3, c);
	}
	
	private function stopAllWatching():Void
	{
		swfWatcher_mc.stopAllWatching();
	}
	
	private function watchProgress(mc:MovieClip):Void
	{
		var currentWatchID:Number = swfWatcher_mc.startWatching(mc);
	}
	
	private function onMovieDone(event_obj:Object):Void
	{
		swfWatcher_mc.stopWatching(event_obj.id);
		// is it the last SWF?
		var movieIndex:Number = -1;
		if(swf_array != null)
		{
			var howMany:Number = swf_array.length;
			if(howMany > 0)
			{
				var currentSWF:String = content_ldr.contentPath;
				var i:Number = howMany;
				while(i--)
				{
					var item:Object = swf_array.getItemAt(i);
					if(item.data == currentSWF)
					{
						movieIndex = i;
						break;
					}
				}
			}
			else
			{
				return;
			}
		}
		else
		{
			return;
		}
		
		if(movieIndex == -1)
		{
			return;
		}
		else if(movieIndex == swf_array.length - 1)
		{
			// it is the last one, should we loop?
			trace("_loop: " + _loop);
			if(_loop == true)
			{
				var item:Object = sections_mnu.getItemAt(0);
				trace("item: " + item);
				updateShown(item);
				var swf:String = item.attributes.instanceName;
				showMovie(swf);
				trace("swf: " + swf);
				return;
			}
			else
			{
				// well, we're done showing all movies
				return;
			}
		}
		
		// we've made it this far, that means there's more to play
		// now, should we care?
		if(_continousPlayback == true)
		{
			var item:Object = sections_mnu.getItemAt(movieIndex + 1);
			if(item == null)
			{
				// wtf? my code above must suck
				return;
			}
			updateShown(item);
			var swf:String = item.attributes.instanceName;
			showMovie(swf);
			return;
		}
	}
	
	private function change(event_obj:Object):Void
	{
		switch(event_obj.menu)
		{
			case sections_mnu:
				var item = event_obj.menuItem;
				updateShown(item);
				var swf:String = item.attributes.instanceName;
				showMovie(swf);
				break;
				
			case prefs_mnu:
				trace("event_obj.menuItem.attributes.instanceName: " + event_obj.menuItem.attributes.instanceName);
				switch(event_obj.menuItem.attributes.instanceName)
				{
					case "scale":
						content_ldr.scaleContent = event_obj.menuItem.attributes.selected;
						size();
						break;
						
					case "mute":
						var bool:Boolean = event_obj.menuItem.attributes.selected;
						if(bool == true)
						{
							oldVolume = slider_mc.sliderValue;
							slider_mc.sliderValue = 0;
						}
						else
						{
							slider_mc.sliderValue = oldVolume;
						}
						break;
					
					case "continous":
						var bool:Boolean = event_obj.menuItem.attributes.selected;
						continousPlayback = bool;
						break;
						
					case "loop":
						var bool:Boolean = event_obj.menuItem.attributes.selected;
						isLooping = bool;
						break;
				}
		}
	}
	
	private function onSlide(event_obj:Object):Void
	{
		my_sound.setVolume(event_obj.sliderValue);
		
		if(menusInited == false)
			return;
			
		var item = prefs_mnu.getItemAt(1);
		if(event_obj.sliderValue == 0)
		{
			if(item.attributes.selected == false)
			{
				item.attributes.selected = true;
				prefs_mnu.replaceItemAt(1, item);
			}
		}
		else
		{
			if(item.attributes.selected)
			{
				item.attributes.selected = false;
				prefs_mnu.replaceItemAt(1, item);
			}
		}
	}
	
	private function showMovie(filepath:String):Void
	{
		if(filepath.length > 0)
		{
			stopAllWatching();
			content_ldr.contentPath = "";
			content_ldr.contentPath = filepath;
			progress_window.deletePopUp();
			progress_window = PopUpManager.createPopUp(this, ProgressBar, false);
			progress_window.move((Stage.width / 2) - (progress_window.width / 2),
							 menu_mb.y + menu_mb.height + 20);
			progress_window.mode = "manual";
			progress_window.indeterminate = true;
			progress_window.label = "Loading Section...";
		}
	}
	
	private function progress(event_obj:Object):Void
	{
		var a:Number = content_ldr.percentLoaded;
		progress_window.indeterminate = false;
		progress_window.setProgress(a, 100);
		content_ldr.content.gotoAndStop(1);
	}
	
	private function complete(event_obj:Object):Void
	{
		progress_window.deletePopUp();
		content_ldr._lockroot = true;
		content_ldr.content.gotoAndPlay(1);
		my_sound.setVolume(slider_mc.sliderValue);
		
		// TODO: make more efficient in the future
		// by not watching unless we have to
		
		//if(_continousPlayback == true || _loop == true)
		//{
			stopAllWatching();
			watchProgress(content_ldr.content);
		//}
	}
	
	private function modelChanged(event_obj:Object):Void
	{
		initMenus();
	}
	
	[Event("playlistLoaded")]
	private function onSWFListLoaded(event_obj:Object):Void
	{
		enabled = true;
		dataProvider = event_obj.results;
		if(event_obj.autoplay != null)
		{
			autoPlay = event_obj.autoplay;
		}
		
		if(event_obj.scalecontent != null)
		{
			scaleContent = event_obj.scalecontent;
		}
		//debug("volume from xml: " + event_obj.volume);
		if(event_obj.volume != null)
		{
			//debug("setting volume to " + event_obj.volume);
			volume = event_obj.volume;
			//debug("volume is now " + volume);
		}
		
		if(event_obj.continousplayback != null)
		{
			continousPlayback = event_obj.continousplayback;
		}
		else
		{
			continousPlayback = true;
		}
		
		if(event_obj.looping != null)
		{
			isLooping = event_obj.looping;
		}
		else
		{
			isLooping = false;
		}
		
		if(autoPlay)
		{
			var item = sections_mnu.getItemAt(0);
			updateShown(item);
			var swf:String = item.attributes.instanceName;
			showMovie(swf);
		}
		
		dispatchEvent({type: "playlistLoaded", target: this});
	}
}